home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / rdflib / Graph.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  52.7 KB  |  1,241 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. from __future__ import generators
  5. __doc__ = '\nInstanciating Graphs with default store (IOMemory) and default identifier (a BNode):\n\n    >>> g=Graph()\n    >>> g.store.__class__\n    <class \'rdflib.store.IOMemory.IOMemory\'>\n    >>> g.identifier.__class__\n    <class \'rdflib.BNode.BNode\'>\n\nInstanciating Graphs with a specific kind of store (IOMemory) and a default identifier (a BNode):\n\nOther store kinds: Sleepycat, MySQL, ZODB, SQLite\n\n    >>> store = plugin.get(\'IOMemory\',Store)()\n    >>> store.__class__.__name__\n    \'IOMemory\'\n    >>> graph = Graph(store)\n    >>> graph.store.__class__\n    <class \'rdflib.store.IOMemory.IOMemory\'>\n\nInstanciating Graphs with Sleepycat store and an identifier - <http://rdflib.net>:\n\n    >>> g=Graph(\'Sleepycat\',URIRef("http://rdflib.net"))\n    >>> g.identifier\n    rdflib.URIRef(\'http://rdflib.net\')\n    >>> str(g)\n    "<http://rdflib.net> a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label \'Sleepycat\']."\n\nCreating a ConjunctiveGraph - The top level container for all named Graphs in a \'database\':\n\n    >>> g=ConjunctiveGraph()\n    >>> str(g.default_context)\n    "[a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label \'IOMemory\']]."\n\nAdding / removing reified triples to Graph and iterating over it directly or via triple pattern:\n    \n    >>> g=Graph(\'IOMemory\')\n    >>> statementId = BNode()\n    >>> print len(g)\n    0\n    >>> g.add((statementId,RDF.type,RDF.Statement))\n    >>> g.add((statementId,RDF.subject,URIRef(\'http://rdflib.net/store/ConjunctiveGraph\')))\n    >>> g.add((statementId,RDF.predicate,RDFS.label))\n    >>> g.add((statementId,RDF.object,Literal("Conjunctive Graph")))\n    >>> print len(g)\n    4\n    >>> for s,p,o in g:  print type(s)\n    ...\n    <class \'rdflib.BNode.BNode\'>\n    <class \'rdflib.BNode.BNode\'>\n    <class \'rdflib.BNode.BNode\'>\n    <class \'rdflib.BNode.BNode\'>\n    \n    >>> for s,p,o in g.triples((None,RDF.object,None)):  print o\n    ...\n    Conjunctive Graph\n    >>> g.remove((statementId,RDF.type,RDF.Statement))\n    >>> print len(g)\n    3\n\nNone terms in calls to triple can be thought of as \'open variables\'  \n\nGraph Aggregation - ConjunctiveGraphs and ReadOnlyGraphAggregate within the same store:\n    \n    >>> store = plugin.get(\'IOMemory\',Store)()\n    >>> g1 = Graph(store)\n    >>> g2 = Graph(store)\n    >>> g3 = Graph(store)\n    >>> stmt1 = BNode()\n    >>> stmt2 = BNode()\n    >>> stmt3 = BNode()\n    >>> g1.add((stmt1,RDF.type,RDF.Statement))\n    >>> g1.add((stmt1,RDF.subject,URIRef(\'http://rdflib.net/store/ConjunctiveGraph\')))\n    >>> g1.add((stmt1,RDF.predicate,RDFS.label))\n    >>> g1.add((stmt1,RDF.object,Literal("Conjunctive Graph")))\n    >>> g2.add((stmt2,RDF.type,RDF.Statement))\n    >>> g2.add((stmt2,RDF.subject,URIRef(\'http://rdflib.net/store/ConjunctiveGraph\')))\n    >>> g2.add((stmt2,RDF.predicate,RDF.type))\n    >>> g2.add((stmt2,RDF.object,RDFS.Class))\n    >>> g3.add((stmt3,RDF.type,RDF.Statement))\n    >>> g3.add((stmt3,RDF.subject,URIRef(\'http://rdflib.net/store/ConjunctiveGraph\')))\n    >>> g3.add((stmt3,RDF.predicate,RDFS.comment))\n    >>> g3.add((stmt3,RDF.object,Literal("The top-level aggregate graph - The sum of all named graphs within a Store")))\n    >>> len(list(ConjunctiveGraph(store).subjects(RDF.type,RDF.Statement)))\n    3\n    >>> len(list(ReadOnlyGraphAggregate([g1,g2]).subjects(RDF.type,RDF.Statement)))\n    2\n\nConjunctiveGraphs have a \'quads\' method which returns quads instead of triples, where the fourth item\nis the Graph (or subclass thereof) instance in which the triple was asserted:\n    \n    >>> from sets import Set    \n    >>> uniqueGraphNames = Set([graph.identifier for s,p,o,graph in ConjunctiveGraph(store).quads((None,RDF.predicate,None))])\n    >>> len(uniqueGraphNames)\n    3\n    >>> unionGraph = ReadOnlyGraphAggregate([g1,g2])\n    >>> uniqueGraphNames = Set([graph.identifier for s,p,o,graph in unionGraph.quads((None,RDF.predicate,None))])\n    >>> len(uniqueGraphNames)\n    2\n     \nParsing N3 from StringIO\n\n    >>> g2=Graph()\n    >>> src = """\n    ... @prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n    ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n    ... [ a rdf:Statement ;\n    ...   rdf:subject <http://rdflib.net/store#ConjunctiveGraph>;\n    ...   rdf:predicate rdfs:label;\n    ...   rdf:object "Conjunctive Graph" ] """\n    >>> g2=g2.parse(StringIO(src),format=\'n3\')\n    >>> print len(g2)\n    4\n\nUsing Namespace class:\n\n    >>> RDFLib = Namespace(\'http://rdflib.net\')\n    >>> RDFLib.ConjunctiveGraph\n    rdflib.URIRef(\'http://rdflib.netConjunctiveGraph\')\n    >>> RDFLib[\'Graph\']\n    rdflib.URIRef(\'http://rdflib.netGraph\')\n\nSPARQL Queries\n\n    >>> print len(g)\n    3\n    >>> q = \'\'\'\n    ... PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> SELECT ?pred WHERE { ?stmt rdf:predicate ?pred. }\n    ... \'\'\'   \n    >>> for pred in g.query(q):  print pred\n    (rdflib.URIRef(\'http://www.w3.org/2000/01/rdf-schema#label\'),)\n\nSPARQL Queries with namespace bindings as argument\n\n    >>> nsMap = {u"rdf":RDF.RDFNS}\n    >>> for pred in g.query("SELECT ?pred WHERE { ?stmt rdf:predicate ?pred. }", initNs=nsMap): print pred\n    (rdflib.URIRef(\'http://www.w3.org/2000/01/rdf-schema#label\'),)\n\nParameterized SPARQL Queries\n\n    >>> top = { Variable("?term") : RDF.predicate }\n    >>> for pred in g.query("SELECT ?pred WHERE { ?stmt ?term ?pred. }", initBindings=top): print pred\n    (rdflib.URIRef(\'http://www.w3.org/2000/01/rdf-schema#label\'),)\n\n'
  6. from cStringIO import StringIO
  7. from rdflib import URIRef, BNode, Namespace, Literal, Variable
  8. from rdflib import RDF, RDFS
  9. from rdflib.Node import Node
  10. from rdflib import plugin, exceptions
  11. from rdflib.store import Store
  12. from rdflib.syntax.serializer import Serializer
  13. from rdflib.syntax.parsers import Parser
  14. from rdflib.syntax.NamespaceManager import NamespaceManager
  15. from rdflib import sparql
  16. from rdflib.QueryResult import QueryResult
  17. from rdflib.URLInputSource import URLInputSource
  18. from xml.sax.xmlreader import InputSource
  19. from xml.sax.saxutils import prepare_input_source
  20. import logging
  21. _logger = logging.getLogger('rdflib.Graph')
  22. import random
  23. import warnings
  24.  
  25. try:
  26.     from hashlib import md5
  27. except ImportError:
  28.     from md5 import md5
  29.  
  30.  
  31. class Graph(Node):
  32.     '''An RDF Graph
  33.  
  34.     The constructor accepts one argument, the \'store\'
  35.     that will be used to store the graph data (see the \'store\'
  36.     package for stores currently shipped with rdflib).
  37.  
  38.     Stores can be context-aware or unaware.  Unaware stores take up
  39.     (some) less space but cannot support features that require
  40.     context, such as true merging/demerging of sub-graphs and
  41.     provenance.
  42.  
  43.     The Graph constructor can take an identifier which identifies the Graph
  44.     by name.  If none is given, the graph is assigned a BNode for it\'s identifier.
  45.     For more on named graphs, see: http://www.w3.org/2004/03/trix/
  46.  
  47.     Ontology for __str__ provenance terms:
  48.  
  49.     @prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
  50.     @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
  51.     @prefix : <http://rdflib.net/store#> .
  52.     @prefix rdfg: <http://www.w3.org/2004/03/trix/rdfg-1/>.
  53.     @prefix owl: <http://www.w3.org/2002/07/owl#>.
  54.     @prefix log: <http://www.w3.org/2000/10/swap/log#>.
  55.     @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
  56.  
  57.     :Store a owl:Class;
  58.         rdfs:subClassOf <http://xmlns.com/wordnet/1.6/Electronic_database>;
  59.         rdfs:subClassOf
  60.             [a owl:Restriction;
  61.              owl:onProperty rdfs:label;
  62.              owl:allValuesFrom [a owl:DataRange;
  63.                                 owl:oneOf ("IOMemory"
  64.                                            "Sleepcat"
  65.                                            "MySQL"
  66.                                            "Redland"
  67.                                            "REGEXMatching"
  68.                                            "ZODB"
  69.                                            "AuditableStorage"
  70.                                            "Memory")]
  71.             ].
  72.  
  73.     :ConjunctiveGraph a owl:Class;
  74.         rdfs:subClassOf rdfg:Graph;
  75.         rdfs:label "The top-level graph within the store - the union of all the Graphs within."
  76.         rdfs:seeAlso <http://rdflib.net/rdf_store/#ConjunctiveGraph>.
  77.  
  78.     :DefaultGraph a owl:Class;
  79.         rdfs:subClassOf rdfg:Graph;
  80.         rdfs:label "The \'default\' subgraph of a conjunctive graph".
  81.  
  82.  
  83.     :identifier a owl:Datatypeproperty;
  84.         rdfs:label "The store-associated identifier of the formula. ".
  85.         rdfs:domain log:Formula
  86.         rdfs:range xsd:anyURI;
  87.  
  88.     :storage a owl:ObjectProperty;
  89.         rdfs:domain [
  90.             a owl:Class;
  91.             owl:unionOf (log:Formula rdfg:Graph :ConjunctiveGraph)
  92.         ];
  93.         rdfs:range :Store.
  94.  
  95.     :default_context a owl:FunctionalProperty;
  96.         rdfs:label "The default context for a conjunctive graph";
  97.         rdfs:domain :ConjunctiveGraph;
  98.         rdfs:range :DefaultGraph.
  99.  
  100.  
  101.     {?cg a :ConjunctiveGraph;:storage ?store}
  102.       => {?cg owl:sameAs ?store}.
  103.  
  104.     {?subGraph rdfg:subGraphOf ?cg;a :DefaultGraph}
  105.       => {?cg a :ConjunctiveGraph;:default_context ?subGraphOf} .
  106.     '''
  107.     
  108.     def __init__(self, store = 'default', identifier = None, namespace_manager = None):
  109.         super(Graph, self).__init__()
  110.         if not identifier:
  111.             pass
  112.         self._Graph__identifier = BNode()
  113.         if not isinstance(store, Store):
  114.             self._Graph__store = store = plugin.get(store, Store)()
  115.         else:
  116.             self._Graph__store = store
  117.         self._Graph__namespace_manager = namespace_manager
  118.         self.context_aware = False
  119.         self.formula_aware = False
  120.  
  121.     
  122.     def __get_store(self):
  123.         return self._Graph__store
  124.  
  125.     store = property(__get_store)
  126.     
  127.     def __get_identifier(self):
  128.         return self._Graph__identifier
  129.  
  130.     identifier = property(__get_identifier)
  131.     
  132.     def _get_namespace_manager(self):
  133.         if self._Graph__namespace_manager is None:
  134.             self._Graph__namespace_manager = NamespaceManager(self)
  135.         
  136.         return self._Graph__namespace_manager
  137.  
  138.     
  139.     def _set_namespace_manager(self, nm):
  140.         self._Graph__namespace_manager = nm
  141.  
  142.     namespace_manager = property(_get_namespace_manager, _set_namespace_manager)
  143.     
  144.     def __repr__(self):
  145.         return '<Graph identifier=%s (%s)>' % (self.identifier, type(self))
  146.  
  147.     
  148.     def __str__(self):
  149.         if isinstance(self.identifier, URIRef):
  150.             return "%s a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label '%s']." % (self.identifier.n3(), self.store.__class__.__name__)
  151.         return "[a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label '%s']]." % self.store.__class__.__name__
  152.  
  153.     
  154.     def destroy(self, configuration):
  155.         '''Destroy the store identified by `configuration` if supported'''
  156.         self._Graph__store.destroy(configuration)
  157.  
  158.     
  159.     def commit(self):
  160.         '''Commits active transactions'''
  161.         self._Graph__store.commit()
  162.  
  163.     
  164.     def rollback(self):
  165.         '''Rollback active transactions'''
  166.         self._Graph__store.rollback()
  167.  
  168.     
  169.     def open(self, configuration, create = False):
  170.         '''Open the graph store
  171.  
  172.         Might be necessary for stores that require opening a connection to a
  173.         database or acquiring some resource.
  174.         '''
  175.         return self._Graph__store.open(configuration, create)
  176.  
  177.     
  178.     def close(self, commit_pending_transaction = False):
  179.         '''Close the graph store
  180.  
  181.         Might be necessary for stores that require closing a connection to a
  182.         database or releasing some resource.
  183.         '''
  184.         self._Graph__store.close(commit_pending_transaction = commit_pending_transaction)
  185.  
  186.     
  187.     def add(self, .1):
  188.         '''Add a triple with self as context'''
  189.         (s, p, o) = .1
  190.         self._Graph__store.add((s, p, o), self, quoted = False)
  191.  
  192.     
  193.     def addN(self, quads):
  194.         '''Add a sequence of triple with context'''
  195.         [](_[1])
  196.  
  197.     
  198.     def remove(self, .1):
  199.         '''Remove a triple from the graph
  200.  
  201.         If the triple does not provide a context attribute, removes the triple
  202.         from all contexts.
  203.         '''
  204.         (s, p, o) = .1
  205.         self._Graph__store.remove((s, p, o), context = self)
  206.  
  207.     
  208.     def triples(self, .1):
  209.         '''Generator over the triple store
  210.  
  211.         Returns triples that match the given triple pattern. If triple pattern
  212.         does not provide a context, all contexts will be searched.
  213.         '''
  214.         (s, p, o) = .1
  215.         for s, p, o in self._Graph__store.triples((s, p, o), context = self):
  216.             cg = None
  217.             yield (s, p, o)
  218.         
  219.  
  220.     
  221.     def __len__(self):
  222.         '''Returns the number of triples in the graph
  223.  
  224.         If context is specified then the number of triples in the context is
  225.         returned instead.
  226.         '''
  227.         return self._Graph__store.__len__(context = self)
  228.  
  229.     
  230.     def __iter__(self):
  231.         '''Iterates over all triples in the store'''
  232.         return self.triples((None, None, None))
  233.  
  234.     
  235.     def __contains__(self, triple):
  236.         """Support for 'triple in graph' syntax"""
  237.         for triple in self.triples(triple):
  238.             return 1
  239.         
  240.         return 0
  241.  
  242.     
  243.     def __hash__(self):
  244.         return hash(self.identifier)
  245.  
  246.     
  247.     def md5_term_hash(self):
  248.         d = md5(str(self.identifier))
  249.         d.update('G')
  250.         return d.hexdigest()
  251.  
  252.     
  253.     def __cmp__(self, other):
  254.         if other is None:
  255.             return -1
  256.         if isinstance(other, Graph):
  257.             return cmp(self.identifier, other.identifier)
  258.         return 1
  259.  
  260.     
  261.     def __iadd__(self, other):
  262.         '''Add all triples in Graph other to Graph'''
  263.         for triple in other:
  264.             self.add(triple)
  265.         
  266.         return self
  267.  
  268.     
  269.     def __isub__(self, other):
  270.         '''Subtract all triples in Graph other from Graph'''
  271.         for triple in other:
  272.             self.remove(triple)
  273.         
  274.         return self
  275.  
  276.     
  277.     def __add__(self, other):
  278.         '''Set theoretical union'''
  279.         retval = Graph()
  280.         for x in self.graph:
  281.             retval.add(x)
  282.         
  283.         for y in other.graph:
  284.             retval.add(y)
  285.         
  286.         return retval
  287.  
  288.     
  289.     def __mul__(self, other):
  290.         '''Set theoretical intersection'''
  291.         retval = Graph()
  292.         for x in other.graph:
  293.             if x in self.graph:
  294.                 retval.add(x)
  295.                 continue
  296.         
  297.         return retval
  298.  
  299.     
  300.     def __sub__(self, other):
  301.         '''Set theoretical difference'''
  302.         retval = Graph()
  303.         for x in self.graph:
  304.             if x not in other.graph:
  305.                 retval.add(x)
  306.                 continue
  307.         
  308.         return retval
  309.  
  310.     
  311.     def set(self, .1):
  312.         '''Convenience method to update the value of object
  313.  
  314.         Remove any existing triples for subject and predicate before adding
  315.         (subject, predicate, object).
  316.         '''
  317.         (subject, predicate, object) = .1
  318.         self.remove((subject, predicate, None))
  319.         self.add((subject, predicate, object))
  320.  
  321.     
  322.     def subjects(self, predicate = None, object = None):
  323.         '''A generator of subjects with the given predicate and object'''
  324.         for s, p, o in self.triples((None, predicate, object)):
  325.             yield s
  326.         
  327.  
  328.     
  329.     def predicates(self, subject = None, object = None):
  330.         '''A generator of predicates with the given subject and object'''
  331.         for s, p, o in self.triples((subject, None, object)):
  332.             yield p
  333.         
  334.  
  335.     
  336.     def objects(self, subject = None, predicate = None):
  337.         '''A generator of objects with the given subject and predicate'''
  338.         for s, p, o in self.triples((subject, predicate, None)):
  339.             yield o
  340.         
  341.  
  342.     
  343.     def subject_predicates(self, object = None):
  344.         '''A generator of (subject, predicate) tuples for the given object'''
  345.         for s, p, o in self.triples((None, None, object)):
  346.             yield (s, p)
  347.         
  348.  
  349.     
  350.     def subject_objects(self, predicate = None):
  351.         '''A generator of (subject, object) tuples for the given predicate'''
  352.         for s, p, o in self.triples((None, predicate, None)):
  353.             yield (s, o)
  354.         
  355.  
  356.     
  357.     def predicate_objects(self, subject = None):
  358.         '''A generator of (predicate, object) tuples for the given subject'''
  359.         for s, p, o in self.triples((subject, None, None)):
  360.             yield (p, o)
  361.         
  362.  
  363.     
  364.     def triples_choices(self, .1, context = None):
  365.         (subject, predicate, object_) = .1
  366.         for s, p, o in self.store.triples_choices((subject, predicate, object_), context = self):
  367.             cg = None
  368.             yield (s, p, o)
  369.         
  370.  
  371.     
  372.     def value(self, subject = None, predicate = RDF.value, object = None, default = None, any = True):
  373.         """Get a value for a pair of two criteria
  374.  
  375.         Exactly one of subject, predicate, object must be None. Useful if one
  376.         knows that there may only be one value.
  377.  
  378.         It is one of those situations that occur a lot, hence this
  379.         'macro' like utility
  380.  
  381.         Parameters:
  382.         -----------
  383.         subject, predicate, object  -- exactly one must be None
  384.         default -- value to be returned if no values found
  385.         any -- if True:
  386.                  return any value in the case there is more than one
  387.                else:
  388.                  raise UniquenessError
  389.         """
  390.         retval = default
  391.         if not subject is None or predicate is None:
  392.             if (subject is None or object is None or predicate is None) and object is None:
  393.                 return None
  394.             if object is None:
  395.                 values = self.objects(subject, predicate)
  396.             
  397.         if subject is None:
  398.             values = self.subjects(predicate, object)
  399.         
  400.         if predicate is None:
  401.             values = self.predicates(subject, object)
  402.         
  403.         
  404.         try:
  405.             retval = values.next()
  406.         except StopIteration:
  407.             e = None
  408.             retval = default
  409.  
  410.         if any is False:
  411.             
  412.             try:
  413.                 next = values.next()
  414.                 msg = 'While trying to find a value for (%s, %s, %s) the following multiple values where found:\n' % (subject, predicate, object)
  415.                 triples = self.store.triples((subject, predicate, object), None)
  416.                 for s, p, o in triples:
  417.                     contexts = None
  418.                     msg += '(%s, %s, %s)\n (contexts: %s)\n' % (s, p, o, list(contexts))
  419.                 
  420.                 raise exceptions.UniquenessError(msg)
  421.             except StopIteration:
  422.                 e = None
  423.             except:
  424.                 None<EXCEPTION MATCH>StopIteration
  425.             
  426.  
  427.         None<EXCEPTION MATCH>StopIteration
  428.         return retval
  429.  
  430.     
  431.     def label(self, subject, default = ''):
  432.         '''Query for the RDFS.label of the subject
  433.  
  434.         Return default if no label exists
  435.         '''
  436.         if subject is None:
  437.             return default
  438.         return self.value(subject, RDFS.label, default = default, any = True)
  439.  
  440.     
  441.     def comment(self, subject, default = ''):
  442.         '''Query for the RDFS.comment of the subject
  443.  
  444.         Return default if no comment exists
  445.         '''
  446.         if subject is None:
  447.             return default
  448.         return self.value(subject, RDFS.comment, default = default, any = True)
  449.  
  450.     
  451.     def items(self, list):
  452.         '''Generator over all items in the resource specified by list
  453.  
  454.         list is an RDF collection.
  455.         '''
  456.         while list:
  457.             item = self.value(list, RDF.first)
  458.             if item:
  459.                 yield item
  460.             
  461.             list = self.value(list, RDF.rest)
  462.  
  463.     
  464.     def transitive_objects(self, subject, property, remember = None):
  465.         '''Transitively generate objects for the `property` relationship
  466.  
  467.         Generated objects belong to the depth first transitive closure of the
  468.         `property` relationship starting at `subject`.
  469.         '''
  470.         if remember is None:
  471.             remember = { }
  472.         
  473.         if subject in remember:
  474.             return None
  475.         remember[subject] = 1
  476.         yield subject
  477.         subject in remember
  478.         for object in self.objects(subject, property):
  479.             for o in self.transitive_objects(object, property, remember):
  480.                 yield o
  481.             
  482.         
  483.  
  484.     
  485.     def transitive_subjects(self, predicate, object, remember = None):
  486.         '''Transitively generate objects for the `property` relationship
  487.  
  488.         Generated objects belong to the depth first transitive closure of the
  489.         `property` relationship starting at `subject`.
  490.         '''
  491.         if remember is None:
  492.             remember = { }
  493.         
  494.         if object in remember:
  495.             return None
  496.         remember[object] = 1
  497.         yield object
  498.         object in remember
  499.         for subject in self.subjects(predicate, object):
  500.             for s in self.transitive_subjects(predicate, subject, remember):
  501.                 yield s
  502.             
  503.         
  504.  
  505.     
  506.     def seq(self, subject):
  507.         '''Check if subject is an rdf:Seq
  508.  
  509.         If yes, it returns a Seq class instance, None otherwise.
  510.         '''
  511.         if (subject, RDF.type, RDF.Seq) in self:
  512.             return Seq(self, subject)
  513.         return None
  514.  
  515.     
  516.     def qname(self, uri):
  517.         return self.namespace_manager.qname(uri)
  518.  
  519.     
  520.     def compute_qname(self, uri):
  521.         return self.namespace_manager.compute_qname(uri)
  522.  
  523.     
  524.     def bind(self, prefix, namespace, override = True):
  525.         '''Bind prefix to namespace
  526.  
  527.         If override is True will bind namespace to given prefix if namespace
  528.         was already bound to a different prefix.
  529.         '''
  530.         return self.namespace_manager.bind(prefix, namespace, override = override)
  531.  
  532.     
  533.     def namespaces(self):
  534.         '''Generator over all the prefix, namespace tuples'''
  535.         for prefix, namespace in self.namespace_manager.namespaces():
  536.             yield (prefix, namespace)
  537.         
  538.  
  539.     
  540.     def absolutize(self, uri, defrag = 1):
  541.         """Turn uri into an absolute URI if it's not one already"""
  542.         return self.namespace_manager.absolutize(uri, defrag)
  543.  
  544.     
  545.     def serialize(self, destination = None, format = 'xml', base = None, encoding = None, **args):
  546.         '''Serialize the Graph to destination
  547.  
  548.         If destination is None serialize method returns the serialization as a
  549.         string. Format defaults to xml (AKA rdf/xml).
  550.         '''
  551.         serializer = plugin.get(format, Serializer)(self)
  552.         return serializer.serialize(destination, base = base, encoding = encoding, **args)
  553.  
  554.     
  555.     def prepare_input_source(self, source, publicID = None):
  556.         if isinstance(source, InputSource):
  557.             input_source = source
  558.         elif hasattr(source, 'read') and not isinstance(source, Namespace):
  559.             input_source = prepare_input_source(source)
  560.         else:
  561.             location = self.absolutize(source)
  562.             input_source = URLInputSource(location)
  563.             if not publicID:
  564.                 pass
  565.             publicID = location
  566.         if publicID:
  567.             input_source.setPublicId(publicID)
  568.         
  569.         id = input_source.getPublicId()
  570.         if id is None:
  571.             input_source.setPublicId('')
  572.         
  573.         return input_source
  574.  
  575.     
  576.     def parse(self, source, publicID = None, format = 'xml', **args):
  577.         """ Parse source into Graph
  578.  
  579.         If Graph is context-aware it'll get loaded into it's own context
  580.         (sub graph). Format defaults to xml (AKA rdf/xml). The publicID
  581.         argument is for specifying the logical URI for the case that it's
  582.         different from the physical source URI. Returns the context into which
  583.         the source was parsed.
  584.         """
  585.         source = self.prepare_input_source(source, publicID)
  586.         parser = plugin.get(format, Parser)()
  587.         parser.parse(source, self, **args)
  588.         return self
  589.  
  590.     
  591.     def load(self, source, publicID = None, format = 'xml'):
  592.         self.parse(source, publicID, format)
  593.  
  594.     
  595.     def query(self, strOrQuery, initBindings = { }, initNs = { }, DEBUG = False, processor = 'sparql'):
  596.         """
  597.         Executes a SPARQL query (eventually will support Versa queries with same method) against this Graph
  598.         strOrQuery - Is either a string consisting of the SPARQL query or an instance of rdflib.sparql.bison.Query.Query
  599.         initBindings - A mapping from a Variable to an RDFLib term (used as initial bindings for SPARQL query)
  600.         initNS - A mapping from a namespace prefix to an instance of rdflib.Namespace (used for SPARQL query)
  601.         DEBUG - A boolean flag passed on to the SPARQL parser and evaluation engine
  602.         processor - The kind of RDF query (must be 'sparql' until Versa is ported)
  603.         """
  604.         if not processor == 'sparql':
  605.             raise AssertionError, 'SPARQL is currently the only supported RDF query language'
  606.         p = plugin.get(processor, sparql.Processor)(self)
  607.         return plugin.get('SPARQLQueryResult', QueryResult)(p.query(strOrQuery, initBindings, initNs, DEBUG))
  608.         processor_plugin = plugin.get(processor, sparql.Processor)(self.store)
  609.         qresult_plugin = plugin.get('SPARQLQueryResult', QueryResult)
  610.         res = processor_plugin.query(strOrQuery, initBindings, initNs, DEBUG)
  611.         return qresult_plugin(res)
  612.  
  613.     
  614.     def n3(self):
  615.         '''return an n3 identifier for the Graph'''
  616.         return '[%s]' % self.identifier.n3()
  617.  
  618.     
  619.     def __reduce__(self):
  620.         return (Graph, (self.store, self.identifier))
  621.  
  622.     
  623.     def isomorphic(self, other):
  624.         if len(self) != len(other):
  625.             return False
  626.         for s, p, o in self:
  627.             if not isinstance(s, BNode) and not isinstance(o, BNode):
  628.                 if (s, p, o) not in other:
  629.                     return False
  630.                 continue
  631.             (s, p, o) not in other
  632.         
  633.         for s, p, o in other:
  634.             if not isinstance(s, BNode) and not isinstance(o, BNode):
  635.                 if (s, p, o) not in self:
  636.                     return False
  637.                 continue
  638.             (s, p, o) not in self
  639.         
  640.         return True
  641.  
  642.     
  643.     def connected(self):
  644.         '''Check if the Graph is connected
  645.  
  646.         The Graph is considered undirectional.
  647.  
  648.         Performs a search on the Graph, starting from a random node. Then
  649.         iteratively goes depth-first through the triplets where the node is
  650.         subject and object. Return True if all nodes have been visited and
  651.         False if it cannot continue and there are still unvisited nodes left.
  652.         '''
  653.         all_nodes = list(self.all_nodes())
  654.         discovered = []
  655.         visiting = [
  656.             all_nodes[random.randrange(len(all_nodes))]]
  657.         while visiting:
  658.             x = visiting.pop()
  659.             if x not in discovered:
  660.                 discovered.append(x)
  661.             
  662.             for new_x in self.objects(subject = x):
  663.                 if new_x not in discovered and new_x not in visiting:
  664.                     visiting.append(new_x)
  665.                     continue
  666.             
  667.             for new_x in self.subjects(object = x):
  668.                 if new_x not in discovered and new_x not in visiting:
  669.                     visiting.append(new_x)
  670.                     continue
  671.             
  672.         if len(all_nodes) == len(discovered):
  673.             return True
  674.         return False
  675.  
  676.     
  677.     def all_nodes(self):
  678.         obj = set(self.objects())
  679.         allNodes = obj.union(set(self.subjects()))
  680.         return allNodes
  681.  
  682.  
  683.  
  684. class ConjunctiveGraph(Graph):
  685.     
  686.     def __init__(self, store = 'default', identifier = None):
  687.         super(ConjunctiveGraph, self).__init__(store)
  688.         if not self.store.context_aware:
  689.             raise AssertionError, 'ConjunctiveGraph must be backed by a context aware store.'
  690.         self.context_aware = True
  691.         if not identifier:
  692.             pass
  693.         self.default_context = Graph(store = self.store, identifier = BNode())
  694.  
  695.     
  696.     def __str__(self):
  697.         pattern = "[a rdflib:ConjunctiveGraph;rdflib:storage [a rdflib:Store;rdfs:label '%s']]"
  698.         return pattern % self.store.__class__.__name__
  699.  
  700.     
  701.     def add(self, .1):
  702.         '''Add the triple to the default context'''
  703.         (s, p, o) = .1
  704.         self.store.add((s, p, o), context = self.default_context, quoted = False)
  705.  
  706.     
  707.     def addN(self, quads):
  708.         '''Add a sequence of triple with context'''
  709.         self.store.addN(quads)
  710.  
  711.     
  712.     def remove(self, .1):
  713.         '''Removes from all its contexts'''
  714.         (s, p, o) = .1
  715.         self.store.remove((s, p, o), context = None)
  716.  
  717.     
  718.     def triples(self, .1):
  719.         '''Iterate over all the triples in the entire conjunctive graph'''
  720.         (s, p, o) = .1
  721.         for s, p, o in self.store.triples((s, p, o), context = None):
  722.             cg = None
  723.             yield (s, p, o)
  724.         
  725.  
  726.     
  727.     def quads(self, .1):
  728.         '''Iterate over all the quads in the entire conjunctive graph'''
  729.         (s, p, o) = .1
  730.         for s, p, o in self.store.triples((s, p, o), context = None):
  731.             cg = None
  732.             for ctx in cg:
  733.                 yield (s, p, o, ctx)
  734.             
  735.         
  736.  
  737.     
  738.     def triples_choices(self, .1):
  739.         '''Iterate over all the triples in the entire conjunctive graph'''
  740.         (s, p, o) = .1
  741.         for s1, p1, o1 in self.store.triples_choices((s, p, o), context = None):
  742.             cg = None
  743.             yield (s1, p1, o1)
  744.         
  745.  
  746.     
  747.     def __len__(self):
  748.         '''Number of triples in the entire conjunctive graph'''
  749.         return self.store.__len__()
  750.  
  751.     
  752.     def contexts(self, triple = None):
  753.         '''Iterate over all contexts in the graph
  754.  
  755.         If triple is specified, iterate over all contexts the triple is in.
  756.         '''
  757.         for context in self.store.contexts(triple):
  758.             yield context
  759.         
  760.  
  761.     
  762.     def remove_context(self, context):
  763.         '''Removes the given context from the graph'''
  764.         self.store.remove((None, None, None), context)
  765.  
  766.     
  767.     def context_id(self, uri, context_id = None):
  768.         '''URI#context'''
  769.         uri = uri.split('#', 1)[0]
  770.         if context_id is None:
  771.             context_id = '#context'
  772.         
  773.         return URIRef(context_id, base = uri)
  774.  
  775.     
  776.     def parse(self, source, publicID = None, format = 'xml', **args):
  777.         """Parse source into Graph into it's own context (sub graph)
  778.  
  779.         Format defaults to xml (AKA rdf/xml). The publicID argument is for
  780.         specifying the logical URI for the case that it's different from the
  781.         physical source URI. Returns the context into which the source was
  782.         parsed. In the case of n3 it returns the root context.
  783.         """
  784.         source = self.prepare_input_source(source, publicID)
  785.         id = self.context_id(self.absolutize(source.getPublicId()))
  786.         context = Graph(store = self.store, identifier = id)
  787.         context.remove((None, None, None))
  788.         context.parse(source, publicID = publicID, format = format, **args)
  789.         return context
  790.  
  791.     
  792.     def __reduce__(self):
  793.         return (ConjunctiveGraph, (self.store, self.identifier))
  794.  
  795.  
  796.  
  797. class QuotedGraph(Graph):
  798.     
  799.     def __init__(self, store, identifier):
  800.         super(QuotedGraph, self).__init__(store, identifier)
  801.  
  802.     
  803.     def add(self, triple):
  804.         '''Add a triple with self as context'''
  805.         self.store.add(triple, self, quoted = True)
  806.  
  807.     
  808.     def addN(self, quads):
  809.         '''Add a sequence of triple with context'''
  810.         [](_[1])
  811.  
  812.     
  813.     def n3(self):
  814.         '''Return an n3 identifier for the Graph'''
  815.         return '{%s}' % self.identifier.n3()
  816.  
  817.     
  818.     def __str__(self):
  819.         identifier = self.identifier.n3()
  820.         label = self.store.__class__.__name__
  821.         pattern = "{this rdflib.identifier %s;rdflib:storage [a rdflib:Store;rdfs:label '%s']}"
  822.         return pattern % (identifier, label)
  823.  
  824.     
  825.     def __reduce__(self):
  826.         return (QuotedGraph, (self.store, self.identifier))
  827.  
  828.  
  829.  
  830. class GraphValue(QuotedGraph):
  831.     
  832.     def __init__(self, store, identifier = None, graph = None):
  833.         if graph is not None:
  834.             if not identifier is None:
  835.                 raise AssertionError
  836.             np = store.node_pickler
  837.             identifier = md5()
  838.             s = list(graph.triples((None, None, None)))
  839.             s.sort()
  840.             for t in s:
  841.                 identifier.update(('^'.join,)((lambda .0: for i in .0:
  842. np.dumps(i))(t)))
  843.             
  844.             identifier = URIRef('data:%s' % identifier.hexdigest())
  845.             super(GraphValue, self).__init__(store, identifier)
  846.             for t in graph:
  847.                 store.add(t, context = self)
  848.             
  849.         else:
  850.             super(GraphValue, self).__init__(store, identifier)
  851.  
  852.     
  853.     def add(self, triple):
  854.         raise Exception('not mutable')
  855.  
  856.     
  857.     def remove(self, triple):
  858.         raise Exception('not mutable')
  859.  
  860.     
  861.     def __reduce__(self):
  862.         return (GraphValue, (self.store, self.identifier))
  863.  
  864.  
  865.  
  866. class Seq(object):
  867.     """Wrapper around an RDF Seq resource
  868.  
  869.     It implements a container type in Python with the order of the items
  870.     returned corresponding to the Seq content. It is based on the natural
  871.     ordering of the predicate names _1, _2, _3, etc, which is the
  872.     'implementation' of a sequence in RDF terms.
  873.     """
  874.     
  875.     def __init__(self, graph, subject):
  876.         '''Parameters:
  877.  
  878.         - graph:
  879.             the graph containing the Seq
  880.  
  881.         - subject:
  882.             the subject of a Seq. Note that the init does not
  883.             check whether this is a Seq, this is done in whoever
  884.             creates this instance!
  885.         '''
  886.         _list = self._list = list()
  887.         LI_INDEX = RDF.RDFNS['_']
  888.         for p, o in graph.predicate_objects(subject):
  889.             if p.startswith(LI_INDEX):
  890.                 i = int(p.replace(LI_INDEX, ''))
  891.                 _list.append((i, o))
  892.                 continue
  893.         
  894.         _list.sort()
  895.  
  896.     
  897.     def __iter__(self):
  898.         '''Generator over the items in the Seq'''
  899.         for _, item in self._list:
  900.             yield item
  901.         
  902.  
  903.     
  904.     def __len__(self):
  905.         '''Length of the Seq'''
  906.         return len(self._list)
  907.  
  908.     
  909.     def __getitem__(self, index):
  910.         '''Item given by index from the Seq'''
  911.         (index, item) = self._list.__getitem__(index)
  912.         return item
  913.  
  914.  
  915.  
  916. class BackwardCompatGraph(ConjunctiveGraph):
  917.     
  918.     def __init__(self, backend = 'default'):
  919.         warnings.warn('Use ConjunctiveGraph instead. ( from rdflib.Graph import ConjunctiveGraph )', DeprecationWarning, stacklevel = 2)
  920.         super(BackwardCompatGraph, self).__init__(store = backend)
  921.  
  922.     
  923.     def __get_backend(self):
  924.         return self.store
  925.  
  926.     backend = property(__get_backend)
  927.     
  928.     def open(self, configuration, create = True):
  929.         return ConjunctiveGraph.open(self, configuration, create)
  930.  
  931.     
  932.     def add(self, .1, context = None):
  933.         '''Add to to the given context or to the default context'''
  934.         (s, p, o) = .1
  935.         if context is not None:
  936.             c = self.get_context(context)
  937.             if not c.identifier == context:
  938.                 raise AssertionError, '%s != %s' % (c.identifier, context)
  939.         else:
  940.             c = self.default_context
  941.         self.store.add((s, p, o), context = c, quoted = False)
  942.  
  943.     
  944.     def remove(self, .1, context = None):
  945.         '''Remove from the given context or from the default context'''
  946.         (s, p, o) = .1
  947.         if context is not None:
  948.             context = self.get_context(context)
  949.         
  950.         self.store.remove((s, p, o), context)
  951.  
  952.     
  953.     def triples(self, .1, context = None):
  954.         '''Iterate over all the triples in the entire graph'''
  955.         (s, p, o) = .1
  956.         if context is not None:
  957.             c = self.get_context(context)
  958.             if not c.identifier == context:
  959.                 raise AssertionError
  960.         else:
  961.             c = None
  962.         for s, p, o in self.store.triples((s, p, o), c):
  963.             cg = None
  964.             yield (s, p, o)
  965.         
  966.  
  967.     
  968.     def __len__(self, context = None):
  969.         '''Number of triples in the entire graph'''
  970.         if context is not None:
  971.             context = self.get_context(context)
  972.         
  973.         return self.store.__len__(context)
  974.  
  975.     
  976.     def get_context(self, identifier, quoted = False):
  977.         '''Return a context graph for the given identifier
  978.  
  979.         identifier must be a URIRef or BNode.
  980.         '''
  981.         if not isinstance(identifier, URIRef) and isinstance(identifier, BNode):
  982.             raise AssertionError, type(identifier)
  983.         if quoted:
  984.             if not False:
  985.                 raise AssertionError
  986.             return QuotedGraph(self.store, identifier)
  987.         return Graph(store = self.store, identifier = identifier, namespace_manager = self)
  988.  
  989.     
  990.     def remove_context(self, context):
  991.         '''Remove the given context from the graph'''
  992.         self.store.remove((None, None, None), self.get_context(context))
  993.  
  994.     
  995.     def contexts(self, triple = None):
  996.         '''Iterate over all contexts in the graph
  997.  
  998.         If triple is specified, iterate over all contexts the triple is in.
  999.         '''
  1000.         for context in self.store.contexts(triple):
  1001.             yield context.identifier
  1002.         
  1003.  
  1004.     
  1005.     def subjects(self, predicate = None, object = None, context = None):
  1006.         '''Generate subjects with the given predicate and object'''
  1007.         for s, p, o in self.triples((None, predicate, object), context):
  1008.             yield s
  1009.         
  1010.  
  1011.     
  1012.     def predicates(self, subject = None, object = None, context = None):
  1013.         '''Generate predicates with the given subject and object'''
  1014.         for s, p, o in self.triples((subject, None, object), context):
  1015.             yield p
  1016.         
  1017.  
  1018.     
  1019.     def objects(self, subject = None, predicate = None, context = None):
  1020.         '''Generate objects with the given subject and predicate'''
  1021.         for s, p, o in self.triples((subject, predicate, None), context):
  1022.             yield o
  1023.         
  1024.  
  1025.     
  1026.     def subject_predicates(self, object = None, context = None):
  1027.         '''Generate (subject, predicate) tuples for the given object'''
  1028.         for s, p, o in self.triples((None, None, object), context):
  1029.             yield (s, p)
  1030.         
  1031.  
  1032.     
  1033.     def subject_objects(self, predicate = None, context = None):
  1034.         '''Generate (subject, object) tuples for the given predicate'''
  1035.         for s, p, o in self.triples((None, predicate, None), context):
  1036.             yield (s, o)
  1037.         
  1038.  
  1039.     
  1040.     def predicate_objects(self, subject = None, context = None):
  1041.         '''Generate (predicate, object) tuples for the given subject'''
  1042.         for s, p, o in self.triples((subject, None, None), context):
  1043.             yield (p, o)
  1044.         
  1045.  
  1046.     
  1047.     def __reduce__(self):
  1048.         return (BackwardCompatGraph, (self.store, self.identifier))
  1049.  
  1050.     
  1051.     def save(self, destination, format = 'xml', base = None, encoding = None):
  1052.         warnings.warn('Use serialize method instead. ', DeprecationWarning, stacklevel = 2)
  1053.         self.serialize(destination = destination, format = format, base = base, encoding = encoding)
  1054.  
  1055.  
  1056.  
  1057. class ModificationException(Exception):
  1058.     
  1059.     def __init__(self):
  1060.         pass
  1061.  
  1062.     
  1063.     def __str__(self):
  1064.         return 'Modifications and transactional operations not allowed on ReadOnlyGraphAggregate instances'
  1065.  
  1066.  
  1067.  
  1068. class UnSupportedAggregateOperation(Exception):
  1069.     
  1070.     def __init__(self):
  1071.         pass
  1072.  
  1073.     
  1074.     def __str__(self):
  1075.         return 'This operation is not supported by ReadOnlyGraphAggregate instances'
  1076.  
  1077.  
  1078.  
  1079. class ReadOnlyGraphAggregate(ConjunctiveGraph):
  1080.     '''Utility class for treating a set of graphs as a single graph
  1081.  
  1082.     Only read operations are supported (hence the name). Essentially a
  1083.     ConjunctiveGraph over an explicit subset of the entire store.
  1084.     '''
  1085.     
  1086.     def __init__(self, graphs, store = 'default'):
  1087.         if store is not None:
  1088.             super(ReadOnlyGraphAggregate, self).__init__(store)
  1089.         
  1090.         if not isinstance(graphs, list) and graphs or _[1]:
  1091.             raise AssertionError, 'graphs argument must be a list of Graphs!!'
  1092.         self.graphs = graphs
  1093.  
  1094.     
  1095.     def __repr__(self):
  1096.         return '<ReadOnlyGraphAggregate: %s graphs>' % len(self.graphs)
  1097.  
  1098.     
  1099.     def destroy(self, configuration):
  1100.         raise ModificationException()
  1101.  
  1102.     
  1103.     def commit(self):
  1104.         raise ModificationException()
  1105.  
  1106.     
  1107.     def rollback(self):
  1108.         raise ModificationException()
  1109.  
  1110.     
  1111.     def open(self, configuration, create = False):
  1112.         for graph in self.graphs:
  1113.             graph.open(self, configuration, create)
  1114.         
  1115.  
  1116.     
  1117.     def close(self):
  1118.         for graph in self.graphs:
  1119.             graph.close()
  1120.         
  1121.  
  1122.     
  1123.     def add(self, .1):
  1124.         (s, p, o) = .1
  1125.         raise ModificationException()
  1126.  
  1127.     
  1128.     def addN(self, quads):
  1129.         raise ModificationException()
  1130.  
  1131.     
  1132.     def remove(self, .1):
  1133.         (s, p, o) = .1
  1134.         raise ModificationException()
  1135.  
  1136.     
  1137.     def triples(self, .1):
  1138.         (s, p, o) = .1
  1139.         for graph in self.graphs:
  1140.             for s1, p1, o1 in graph.triples((s, p, o)):
  1141.                 yield (s1, p1, o1)
  1142.             
  1143.         
  1144.  
  1145.     
  1146.     def quads(self, .1):
  1147.         '''Iterate over all the quads in the entire aggregate graph'''
  1148.         (s, p, o) = .1
  1149.         for graph in self.graphs:
  1150.             for s1, p1, o1 in graph.triples((s, p, o)):
  1151.                 yield (s1, p1, o1, graph)
  1152.             
  1153.         
  1154.  
  1155.     
  1156.     def __len__(self):
  1157.         return []([], [ len(g) for g in self.graphs ])
  1158.  
  1159.     
  1160.     def __hash__(self):
  1161.         raise UnSupportedAggregateOperation()
  1162.  
  1163.     
  1164.     def __cmp__(self, other):
  1165.         if other is None:
  1166.             return -1
  1167.         if isinstance(other, Graph):
  1168.             return -1
  1169.         if isinstance(other, ReadOnlyGraphAggregate):
  1170.             return cmp(self.graphs, other.graphs)
  1171.         return -1
  1172.  
  1173.     
  1174.     def __iadd__(self, other):
  1175.         raise ModificationException()
  1176.  
  1177.     
  1178.     def __isub__(self, other):
  1179.         raise ModificationException()
  1180.  
  1181.     
  1182.     def triples_choices(self, .1, context = None):
  1183.         (subject, predicate, object_) = .1
  1184.         for graph in self.graphs:
  1185.             choices = graph.triples_choices((subject, predicate, object_))
  1186.             for s, p, o in choices:
  1187.                 yield (s, p, o)
  1188.             
  1189.         
  1190.  
  1191.     
  1192.     def qname(self, uri):
  1193.         raise UnSupportedAggregateOperation()
  1194.  
  1195.     
  1196.     def compute_qname(self, uri):
  1197.         raise UnSupportedAggregateOperation()
  1198.  
  1199.     
  1200.     def bind(self, prefix, namespace, override = True):
  1201.         raise UnSupportedAggregateOperation()
  1202.  
  1203.     
  1204.     def namespaces(self):
  1205.         if hasattr(self, 'namespace_manager'):
  1206.             for prefix, namespace in self.namespace_manager.namespaces():
  1207.                 yield (prefix, namespace)
  1208.             
  1209.         else:
  1210.             for graph in self.graphs:
  1211.                 for prefix, namespace in graph.namespaces():
  1212.                     yield (prefix, namespace)
  1213.                 
  1214.             
  1215.  
  1216.     
  1217.     def absolutize(self, uri, defrag = 1):
  1218.         raise UnSupportedAggregateOperation()
  1219.  
  1220.     
  1221.     def parse(self, source, publicID = None, format = 'xml', **args):
  1222.         raise ModificationException()
  1223.  
  1224.     
  1225.     def n3(self):
  1226.         raise UnSupportedAggregateOperation()
  1227.  
  1228.     
  1229.     def __reduce__(self):
  1230.         raise UnSupportedAggregateOperation()
  1231.  
  1232.  
  1233.  
  1234. def test():
  1235.     import doctest
  1236.     doctest.testmod()
  1237.  
  1238. if __name__ == '__main__':
  1239.     test()
  1240.  
  1241.